from insts.inst import NoOperandInstruction
from jthread.operand_stack import OperandStack


class POP_STACK(NoOperandInstruction):
    def __init__(self, opcode):  # Constructor
        super().__init__(opcode)  # Call the superclass constructor
        self.index = 0

    def execute(self, frame):
        stack = frame.getOperandStack()
        while self.index > 0:
            stack.popRef()
            self.index -= 1


class POP(POP_STACK):
    def __init__(self, opcode):  # Constructor
        super().__init__(opcode)  # Call the superclass constructor
        self.index = 1


class POP2(POP_STACK):
    def __init__(self, opcode):  # Constructor
        super().__init__(opcode)  # Call the superclass constructor
        self.index = 2


class DUP_STACK(NoOperandInstruction):
    def __init__(self, opcode):  # Constructor
        super().__init__(opcode)  # Call the superclass constructor
        self.kind = 'dup'

    def execute(self, frame):
        stack: OperandStack = frame.getOperandStack()
        if self.kind == 'dup':
            v = stack.popSlot()
            stack.pushSlot(v)
            stack.pushSlot(v)
        elif self.kind == 'dup_x1':
            v2 = stack.popSlot()
            v1 = stack.popSlot()
            stack.pushSlot(v2)
            stack.pushSlot(v1)
            stack.pushSlot(v2)

        elif self.kind == 'dup_x2':
            v3 = stack.popSlot()
            v2 = stack.popSlot()
            v1 = stack.popSlot()
            stack.pushSlot(v3)
            stack.pushSlot(v1)
            stack.pushSlot(v2)
            stack.pushSlot(v3)

        elif self.kind == 'dup2':
            v2 = stack.popSlot()
            v1 = stack.popSlot()
            stack.pushSlot(v1)
            stack.pushSlot(v2)
            stack.pushSlot(v1)
            stack.pushSlot(v2)

        elif self.kind == 'dup2_x1':
            v3 = stack.popSlot()
            v2 = stack.popSlot()
            v1 = stack.popSlot()
            stack.pushSlot(v2)
            stack.pushSlot(v3)
            stack.pushSlot(v1)
            stack.pushSlot(v2)
            stack.pushSlot(v3)

        elif self.kind == 'dup2_x2':
            v4 = stack.popSlot()
            v3 = stack.popSlot()
            v2 = stack.popSlot()
            v1 = stack.popSlot()
            stack.pushSlot(v3)
            stack.pushSlot(v4)
            stack.pushSlot(v1)
            stack.pushSlot(v2)
            stack.pushSlot(v3)
            stack.pushSlot(v4)


class DUP(DUP_STACK):
    def __init__(self, opcode):  # Constructor
        super().__init__(opcode)  # Call the superclass constructor
        self.kind = 'dup'


class DUP_X1(DUP_STACK):
    def __init__(self, opcode):  # Constructor
        super().__init__(opcode)  # Call the superclass constructor
        self.kind = 'dup_x1'


class DUP_X2(DUP_STACK):
    def __init__(self, opcode):  # Constructor
        super().__init__(opcode)  # Call the superclass constructor
        self.kind = 'dup_x2'


class DUP2(DUP_STACK):
    def __init__(self, opcode):  # Constructor
        super().__init__(opcode)  # Call the superclass constructor
        self.kind = 'dup2'


class DUP2_X1(DUP_STACK):
    def __init__(self, opcode):  # Constructor
        super().__init__(opcode)  # Call the superclass constructor
        self.kind = 'dup2_x1'


class DUP2_X2(DUP_STACK):
    def __init__(self, opcode):  # Constructor
        super().__init__(opcode)  # Call the superclass constructor
        self.kind = 'dup2_x2'


class SWAP(NoOperandInstruction):
    def __init__(self, opcode):  # Constructor
        super().__init__(opcode)  # Call the superclass constructor

    def execute(self, frame):
        stack: OperandStack = frame.getOperandStack()
        v2 = stack.popSlot()
        v1 = stack.popSlot()
        stack.pushSlot(v2)
        stack.pushSlot(v1)
